#include "memcache_connection.h"
#include "log.h"

namespace edm{
namespace network{
    
memcache_connection_t::memcache_connection_t(const std::string& address,const std::string& port):
m_connected(false),m_address(address),m_port(port),
m_memc(),m_servers(NULL)
{
    logtrace((MYNET, "memcache_connection_t::memcache_connection_t <%s:%s>", address.c_str(), port.c_str()));
}

memcache_connection_t::~memcache_connection_t()
{
    logtrace((MYNET, "memcache_connection_t::~memcache_connection_t begin ..."));
    if(m_connected) close();
    logtrace((MYNET, "memcache_connection_t::~memcache_connection_t end ok."));	
}

int memcache_connection_t::connect()
{
    logtrace((MYNET, "memcache_connection_t::connect <%s:%s> begin ...", m_address.c_str(), m_port.c_str()));
    if(m_connected)
    {
       logwarn((MYNET, "memcache_connection_t::connect <%s:%d> already connected.", m_address.c_str(), m_port.c_str()));
       return 0;
    }
    memcached_create(&m_memc);

    std::string servers_list;
    servers_list.append(m_address);
    servers_list.append(":");
    servers_list.append(m_port);
    m_servers= memcached_servers_parse(servers_list.c_str());
    memcached_server_push(&m_memc, m_servers);

    m_connected = true;
    logtrace((MYNET, "memcache_connection_t::connect end ok."));	    
    return 0;
}

int memcache_connection_t::close()
{
    logtrace((MYNET, "memcache_connection_t::close begin ..."));
    if(!m_connected)
    {
        logwarn((MYNET, "memcache_connection_t::connect already disconnected."));
        return 0;
    }

    //memcached_free(&m_memc);
    memcached_server_list_free(m_servers);m_servers = 0;
    memcached_free(&m_memc);
    m_connected = false;		
    logtrace((MYNET, "memcache_connection_t::close end ok."));
    return 0;
}

int memcache_connection_t::reconnect()
{
    logtrace((MYNET, "memcache_connection_t::reconnect begin ..."));
    if(close())
    {
            logerror((MYNET, "memcache_connection_t::reconnect close failed."));
            return -1;	
    }

    if(connect())
    {
            logerror((MYNET, "memcache_connection_t::reconnect connect failed."));
            return -1;	
    }
    logtrace((MYNET, "memcache_connection_t::reconnect end ok."));
    return 0;
}

int memcache_connection_t::set(const std::string& key, const std::vector<char> &value,int store_expiration)
{
    logtrace((MYNET, "memcache_connection_t::set begin ..."));
    if (key.empty() || value.empty())
    {
    logerror((MYNET, "memcache_connection_t::set key or value is null."));  
    return -1;
    }

    memcached_return rc= memcached_set(&m_memc,
                                   key.c_str(), key.length(),
                                   &value[0], value.size(),
                                   store_expiration, 0);
    if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
    {
    logerror((MYNET, "memcache_connection_t::set key failed:%s", memcached_strerror(NULL, rc)));
    return -1;
    }

    logtrace((MYNET, "memcache_connection_t::set end ok."));    
    return 0;
}

int memcache_connection_t::add(const std::string& key, const std::vector<char> &value,int store_expiration)
{
    logtrace((MYNET, "memcache_connection_t::add begin ..."));
    if (key.empty() || value.empty())
    {
    logerror((MYNET, "memcache_connection_t::add key or value is null."));  
    return -1;
    }

    memcached_return rc= memcached_add(&m_memc,
                                   key.c_str(), key.length(),
                                   &value[0], value.size(),
                                   store_expiration, 0);
    if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
    {
    logerror((MYNET, "memcache_connection_t::add key failed:%s", memcached_strerror(NULL, rc)));
    return -1;
    }

    logtrace((MYNET, "memcache_connection_t::add end ok."));    
    return 0;
}

int memcache_connection_t::get(const std::string& key, std::vector<char> &ret_val)
{
    logtrace((MYNET, "memcache_connection_t::get begin ..."));
    if (key.empty())
    {
    logerror((MYNET, "memcache_connection_t::get key is null."));  
    return -1;
    }

    uint32_t flags= 0;
    memcached_return rc;
    size_t value_length= 0;    
    char *value= memcached_get(&m_memc, key.c_str(), key.length(),
                           &value_length, &flags, &rc);
    if(value == NULL)
    {
    logerror((MYNET, "memcache_connection_t::get key failed:%s", memcached_strerror(NULL, rc)));
    return -1;
    }

    ret_val.reserve(value_length);
    ret_val.assign(value, value + value_length);
    free(value);   

    logtrace((MYNET, "memcache_connection_t::get end ok."));    
    return 0;
}

int memcache_connection_t::del(const std::string& key)
{
    logtrace((MYNET, "memcache_connection_t::del begin ..."));
    if (key.empty())
    {
    logerror((MYNET, "memcache_connection_t::del key or value is null."));  
    return -1;
    }

    memcached_return rc= memcached_delete(&m_memc, key.c_str(), key.length(), 0);
    if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND)
    {
    logerror((MYNET, "memcache_connection_t::del key failed:%s", memcached_strerror(NULL, rc)));
    return -1;
    }

    logtrace((MYNET, "memcache_connection_t::del end ok."));    
    return 0;
}

//! enum records begin
int memcache_connection_t::enum_init()
{
    logtrace((MYNET, "memcache_connection_t::enum_init <empty impl>."));
    return 0;
    }

    //! result: -1: error 0: null key left 1: get a key
    int memcache_connection_t::enum_next(std::string& ret_key)
    {
    logtrace((MYNET, "memcache_connection_t::enum_next <empty impl>."));
    return 0;
} 
    
}}
    
